#[cfg(test)]
mod tests {
    use std::time::Duration;
    use tokio::{select, time::sleep};

    use crate::utils::freelock::FreeLock;

    struct Test {
        a: i32,
        b: i32,
        c: String,
        d: String,
    }

    impl Test {
        async fn test1(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.a += 1;
                self.c = format!("aaa {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test2(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.b += 1;
                self.c = format!("bbb {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test3(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.a += 1;
                self.c = format!("ccc {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test4(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.b += 1;
                self.c = format!("ddd {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test5(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.a += 1;
                self.c = format!("eee {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test6(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.b += 1;
                self.c = format!("fff {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn test7(&mut self) {
            for _ in 0..10 {
                sleep(Duration::from_micros(10)).await;
                self.a += 1;
                self.c = format!("ggg {} {}", self.a, self.b);
                println!("{} {} {} {}", self.a, self.b, self.c, self.d);
            }
        }

        async fn aaa(&mut self) -> Result<(), String> {
            sleep(Duration::from_millis(10)).await;
            self.d = "XXXX".to_string();
            Ok(())
        }

        async fn bbb(&mut self) -> Result<(), String> {
            sleep(Duration::from_millis(10)).await;
            self.d = "YYYY".to_string();
            Ok(())
        }
    }

    pub struct Wrap {
        m_t: FreeLock<Test>,
    }

    impl Wrap {
        fn new(t: Test) -> Self {
            Wrap {
                m_t: FreeLock::new(t),
            }
        }

        async fn test1(&self) {
            self.m_t.lock().test1().await;
        }

        async fn test2(&self) {
            self.m_t.lock().test2().await;
        }

        async fn test3(&self) {
            self.m_t.lock().test3().await;
        }

        async fn test4(&self) {
            self.m_t.lock().test4().await;
        }

        async fn test5(&self) {
            self.m_t.lock().test5().await;
        }

        async fn test6(&self) {
            self.m_t.lock().test6().await;
        }

        async fn test7(&self) {
            self.m_t.lock().test7().await;
        }

        async fn test8(&self) {
            let mut v1 = self.m_t.lock();
            let mut v2 = self.m_t.lock();

            for _ in 0..10 {
                select! {
                    _ = v1.aaa() => {}
                    _ = v2.bbb() => {}
                };
            }
        }
    }

    async fn do_test() {
        let t = Test {
            a: 0,
            b: 0,
            c: "".to_string(),
            d: "AAA".to_string(),
        };

        let wrap = Wrap::new(t);

        tokio::join! {
            wrap.test1(),
            wrap.test2(),
            wrap.test3(),
            wrap.test4(),
            wrap.test5(),
            wrap.test6(),
            wrap.test7(),
            wrap.test8()
        };
    }

    #[test]
    fn test_free_lock() {
        let runtime = tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .worker_threads(2)
            .thread_name("test")
            .build()
            .unwrap();
        runtime.block_on(async { do_test().await });
    }
}
